<!DOCTYPE HTML>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" /> 
    <title> - 天地维杰网</title>
    <meta name="keywords" content="系统架构,shutdown,不与天斗,Domino,博客,程序员,架构师,笔记,技术,分享,java,Redis">
    
    <meta property="og:title" content="">
    <meta property="og:site_name" content="天地维杰网">
    <meta property="og:image" content="/img/author.jpg"> 
    <meta name="title" content=" - 天地维杰网" />
    <meta name="description" content="天地维杰网 | 博客 | 软件 | 架构 | Java "> 
    <link rel="shortcut icon" href="http://www.shutdown.cn/img/favicon.ico" />
    <link rel="apple-touch-icon" href="http://www.shutdown.cn/img/apple-touch-icon.png" />
    <link rel="apple-touch-icon-precomposed" href="http://www.shutdown.cn/img/apple-touch-icon.png" />
    <link href="http://www.shutdown.cn/js/vendor/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css" />
    <link href="http://www.shutdown.cn/js/vendor/fancybox/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css" />
    <link href="http://www.shutdown.cn/css/main.css" rel="stylesheet" type="text/css" />
    <link href="http://www.shutdown.cn/css/syntax.css" rel="stylesheet" type="text/css" />
    <script type="text/javascript" id="hexo.configuration">
  var NexT = window.NexT || {};
  var CONFIG = {
    scheme: 'Pisces',
    sidebar: {"position":"left","display":"post"},
     fancybox: true, 
    motion: true
  };
</script>
</head>
<body itemscope itemtype="http://schema.org/WebPage" lang="zh-Hans">
<div class="container one-collumn sidebar-position-left page-home  ">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"> <div class="site-meta  custom-logo ">

  <div class="custom-logo-site-title">
    <a href="http://www.shutdown.cn"  class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <span class="site-title">天地维杰网</span>
      <span class="logo-line-after"><i></i></span>
    </a>
  </div>
  <p class="site-subtitle">人如秋鸿来有信，事若春梦了无痕</p>
</div>

<div class="site-nav-toggle">
  <button>
    <span class="btn-bar"></span>
    <span class="btn-bar"></span>
    <span class="btn-bar"></span>
  </button>
</div>

<nav class="site-nav">
    <ul id="menu" class="menu">
      
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-home"></i> <br />首页
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/redis/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-battery-full"></i> <br />Redis
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/java/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-coffee"></i> <br />java
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/linux/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-linux"></i> <br />linux
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/daily/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-bug"></i> <br />日常问题
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/spring/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-child"></i> <br />Spring和Springboot
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/mac/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-fire"></i> <br />Mac相关
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/middleware/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-gavel"></i> <br />中间件
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/jiagou/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-rocket"></i> <br />架构
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/python/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-ship"></i> <br />python
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/front/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-bolt"></i> <br />前端
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/jvm/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-balance-scale"></i> <br />jvm
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/c/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-battery-empty"></i> <br />c语言
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/post/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-archive"></i> <br />归档
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/about/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-user"></i> <br />关于
          </a>
        </li>
      
      <li class="menu-item menu-item-search">
        <a href="javascript:;" class="popup-trigger"> <i class="menu-item-icon fa fa-search fa-fw"></i> <br /> 搜索</a>
      </li>
    </ul>
    <div class="site-search">
      <div class="popup">
 <span class="search-icon fa fa-search"></span>
 <input type="text" id="local-search-input">
 <div id="local-search-result"></div>
 <span class="popup-btn-close">close</span>
</div>

    </div>
</nav>

 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            
<section id="posts" class="posts-expand">
  <article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">
    <header class="post-header">
      <h1 class="post-title" itemprop="name headline">
        <a class="post-title-link" href="http://www.shutdown.cn/post/redis-bigkey/" itemprop="url">
        
        </a>
      </h1>
      <div class="post-meta">
      <span class="post-time">
<span class="post-meta-item-icon">
    <i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">时间：</span>
<time itemprop="dateCreated" datetime="2016-03-22T13:04:35+08:00" content="0001-01-01">
    0001-01-01
</time>
</span> 
      
      
       <span>
&nbsp; | &nbsp;
<span class="post-meta-item-icon">
    <i class="fa fa-eye"></i>
</span>
<span class="post-meta-item-text">阅读：</span>
<span class="leancloud-visitors-count">690 字 ~4分钟</span>
</span>
      </div>
    </header>
    <div class="post-body" itemprop="articleBody">
    

    

<h2 id="一-什么是bigkey"><strong>一、什么是bigkey</strong></h2>

<p>在Redis中，一个字符串最大512MB，一个二级数据结构（例如hash、list、set、zset）可以存储大约40亿个(2^32-1)个元素，但实际上中如果下面两种情况，我就会认为它是bigkey。</p>

<ul>
<li><strong>字符串类型</strong>：它的big体现在单个value值很大，一般认为超过10KB就是bigkey。</li>
<li><strong>非字符串类型</strong>：哈希、列表、集合、有序集合，它们的big体现在元素个数太多。</li>
</ul>

<h2 id="二-危害"><strong>二、危害</strong></h2>

<p>bigkey可以说就是Redis的老鼠屎，具体表现在：</p>

<h2 id="1-内存空间不均匀">1.内存空间不均匀</h2>

<p>这样会不利于集群对内存的统一管理，存在丢失数据的隐患。</p>

<h2 id="2-超时阻塞">2.超时阻塞</h2>

<p>由于Redis单线程的特性，操作bigkey的通常比较耗时，也就意味着阻塞Redis可能性越大，这样会造成客户端阻塞或者引起故障切换，它们通常出现在慢查询中。</p>

<p>例如，在Redis发现了这样的key，你就等着DBA找你吧。</p>
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">127.0.0.1:6379&gt; hlen big:hash(integer) 
2000000127.0.0.1:6379&gt; hgetall big:hash
1) &#34;a&#34;
2) &#34;1&#34;</code></pre></div>
<h2 id="3-网络拥塞">3.网络拥塞</h2>

<p>bigkey也就意味着每次获取要产生的网络流量较大，假设一个bigkey为1MB，客户端每秒访问量为1000，那么每秒产生1000MB的流量，对于普通的千兆网卡(按照字节算是128MB/s)的服务器来说简直是灭顶之灾，而且一般服务器会采用单机多实例的方式来部署，也就是说一个bigkey可能会对其他实例造成影响，其后果不堪设想。</p>

<h2 id="4-过期删除">4.过期删除</h2>

<p>有个bigkey，它安分守己（只执行简单的命令，例如hget、lpop、zscore等），但它设置了过期时间，当它过期后，会被删除，如果没有使用Redis 4.0的过期异步删除(lazyfree-lazy-expire yes)，就会存在阻塞Redis的可能性，而且这个过期删除不会从主节点的慢查询发现（因为这个删除不是客户端产生的，是内部循环事件，可以从latency命令中获取或者从slave节点慢查询发现）。</p>

<h2 id="5-迁移困难">5.迁移困难</h2>

<p>当需要对bigkey进行迁移（例如Redis cluster的迁移slot），实际上是通过migrate命令来完成的，migrate实际上是通过dump + restore + del三个命令组合成原子命令完成，如果是bigkey，可能会使迁移失败，而且较慢的migrate会阻塞Redis。</p>

<h2 id="三-怎么产生的"><strong>三、怎么产生的？</strong></h2>

<p>一般来说，bigkey的产生都是由于程序设计不当，或者对于数据规模预料不清楚造成的，来看几个：</p>

<p>(1) <strong>社交类</strong>：粉丝列表，如果某些明星或者大v不精心设计下，必是bigkey。</p>

<p>(2) <strong>统计类</strong>：例如按天存储某项功能或者网站的用户集合，除非没几个人用，否则必是bigkey。</p>

<p>(3) <strong>缓存类</strong>：将数据从数据库load出来序列化放到Redis里，这个方式非常常用，但有两个地方需要注意:</p>

<ul>
<li>第一，是不是有必要把所有字段都缓存</li>
<li>第二，有没有相关关联的数据</li>
</ul>

<p>例如遇到过一个例子，该同学将某明星一个专辑下所有视频信息都缓存一个巨大的json中，造成这个json达到6MB，后来这个明星发了一个官宣</p>

<h2 id="四-如何发现"><strong>四、如何发现</strong></h2>

<h2 id="1-redis-cli-bigkeys">1. redis-cli &ndash;bigkeys</h2>

<p>redis-cli提供了&ndash;bigkeys来查找bigkey，例如下面就是一次执行结果：</p>
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">-------- summary -------
Biggest string found &#39;user:1&#39; has 5 bytes
Biggest list found &#39;taskflow:175448&#39; has 97478 items
Biggest set found &#39;redisServerSelect:set:11597&#39; has 49 members
Biggest hash found &#39;loginUser:t:20180905&#39; has 863 fields
Biggest zset found &#39;hotkey:scan:instance:zset&#39; has 3431 members
40 strings with 200 bytes (00.00% of keys, avg size 5.00)
2747619 lists with 14680289 items (99.86% of keys, avg size 5.34)
2855 sets with 10305 members (00.10% of keys, avg size 3.61)
13 hashs with 2433 fields (00.00% of keys, avg size 187.15)
830 zsets with 14098 members (00.03% of keys, avg size 16.99)</code></pre></div>
<p>可以看到&ndash;bigkeys给出了每种数据结构的top 1 bigkey，同时给出了每种数据类型的键值个数以及平均大小。</p>

<p><strong>bigkeys对问题的排查非常方便，但是在使用它时候也有几点需要注意:</strong></p>

<ul>
<li>建议在从节点执行，因为&ndash;bigkeys也是通过scan完成的。</li>
<li>建议在节点本机执行，这样可以减少网络开销。</li>
<li>如果没有从节点，可以使用&ndash;i参数，例如(&ndash;i 0.1 代表100毫秒执行一次)</li>
<li>&ndash;bigkeys只能计算每种数据结构的top1，如果有些数据结构非常多的bigkey，也搞不定，毕竟不是自己写的东西嘛</li>
<li>debug object</li>
</ul>

<p>再来看一个场景：</p>

<p>你好，麻烦帮我查一下Redis里大于10KB的所有key</p>

<p>您好，帮忙查一下Redis中长度大于5000的hash key</p>

<p>是不是发现用&ndash;bigkeys不行了（当然如果改源码也不是太难），但有没有更快捷的方法，Redis提供了debug object ${key}命令获取键值的相关信息：</p>
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">127.0.0.1:6379&gt; hlen big:hash
(integer) 5000000
127.0.0.1:6379&gt; debug object big:hash
Value at:0x7fda95b0cb20 refcount:1 encoding:hashtable serializedlength:87777785 lru:9625559 lru_seconds_idle:2
(1.08s)</code></pre></div>
<p>其中serializedlength表示key对应的value序列化之后的字节数，当然如果是字符串类型，完全看可以执行strlen，例如：</p>
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">127.0.0.1:6379&gt; strlen key
(integer) 947394</code></pre></div>
<p>这样你就可以用scan + debug object的方式遍历Redis所有的键值，找到你需要阈值的数据了。</p>

<p>但是在使用debug object时候一定要注意以下几点：</p>

<ul>
<li>debug object bigkey本身可能就会比较慢，它本身就会存在阻塞Redis的可能</li>
<li>建议在从节点执行</li>
<li>建议在节点本地执行</li>
<li>如果不关系具体字节数，完全可以使用scan + strlen|hlen|llen|scard|zcard替代，他们都是o(1)</li>
</ul>

<h2 id="3-memory-usage">3. memory usage</h2>

<p>上面的debug object可能会比较危险、而且不太准确（序列化后的长度），有没有更准确的呢？Redis 4.0开始提供memory usage命令可以计算每个键值的字节数（自身、以及相关指针开销，具体的细节可查阅相关文章），例如下面是一次执行结果：</p>
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">127.0.0.1:6379&gt; memory usage big:hash
(integer) 318663444</code></pre></div>
<p>下面我们来对比就可以看出来，当前系统就一个key，总内存消耗是400MB左右，memory usage相比debug object还是要精确一些的。</p>
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">127.0.0.1:6379&gt; dbsize
(integer) 1
127.0.0.1:6379&gt; hlen big:hash
(integer) 5000000
#约300MB
127.0.0.1:6379&gt; memory usage big:hash
(integer) 318663444
#约85MB
127.0.0.1:6379&gt; debug object big:hash
Value at:0x7fda95b0cb20 refcount:1 encoding:hashtable serializedlength:87777785 lru:9625814 lru_seconds_idle:9
(1.06s)
127.0.0.1:6379&gt; info memory
# Memory
used_memory_human:402.16M</code></pre></div>
<p>如果你使用Redis 4.0+，你就可以用scan + memory usage(pipeline)了，而且很好的一点是,memory不会执行很慢，当然依然是建议从节点 + 本地 。</p>

<h2 id="4-客户端">4. 客户端</h2>

<p>上面三种方式都有一个问题，就是马后炮，如果想很实时的找到bigkey，一方面你可以试试修改Redis源码，还有一种方式就是可以修改客户端，以jedis为例，可以在关键的出入口加上对应的检测机制，例如以Jedis的获取结果为例子：</p>
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">protected Object readProtocolWithCheckingBroken() {
	Object o = null;
	try {
		o = Protocol.read(inputStream);		return o;
	}catch(JedisConnectionException exc) {
		UsefulDataCollector.collectException(exc, getHostPort(), System.currentTimeMillis());		broken = true;
		throw exc;
	}finally {
		if(o != null) {
			if(o instanceof byte[]) {
				byte[] bytes = (byte[]) o;
				if (bytes.length &gt; threshold) {
					// 做很多事情，例如用ELK完成收集和展示
				}
			}
		}
	}
}</code></pre></div>
<h2 id="5-监控报警">5. 监控报警</h2>

<p>bigkey的大操作，通常会引起客户端输入或者输出缓冲区的异常，Redis提供了info clients里面包含的客户端输入缓冲区的字节数以及输出缓冲区的队列长度，可以重点关注下：</p>

<p>如果想知道具体的客户端，可以使用client list命令来查找</p>
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">redis-cli client list
id=3 addr=127.0.0.1:58500 fd=8 name= age=3978 idle=25 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=26263554 events=r cmd=hgetall</code></pre></div>
<h2 id="6-改源码">6. 改源码</h2>

<p>这个其实也是能做的，但是各方面成本比较高，对于一般公司来说不适用。</p>

<p>建议的最佳实践：</p>

<ul>
<li>Redis端与客户端相结合：&ndash;bigkeys临时用、scan长期做排除隐患（尽可能本地化）、客户端实时监控。</li>
<li>监控报警要跟上</li>
<li>debug object尽量少用</li>
<li>所有数据平台化</li>
<li>要和开发同学强调bigkey的危害</li>
</ul>

<h2 id="五-如何删除"><strong>五、如何删除</strong></h2>

<p>如果发现了bigkey，而且确认是垃圾是不是直接del就可以了，来看一组数据：</p>

<p>可以看到对于string类型，删除速度还是可以接受的。但对于二级数据结构，随着元素个数的增长以及每个元素字节数的增大，删除速度会越来越慢，存在阻塞Redis的隐患。所以在删除它们时候建议采用渐进式的方式来完成：hscan、ltrim、sscan、zscan。</p>

<p>如果你使用Redis 4.0+，一条异步删除unlink就解决，就可以忽略下面内容。</p>

<h2 id="1-字符串">1. 字符串</h2>

<p>一般来说，对于string类型使用del命令不会产生阻塞。</p>
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">del bigkey</code></pre></div>
<h2 id="2-hash">2. hash</h2>

<p>使用hscan命令，每次获取部分(例如100个)field-value，在利用hdel删除每个field(为了快速可以使用pipeline)。</p>
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">public void delBigHash(String bigKey) {
	Jedis jedis = new Jedis(&#34;127.0.0.1&#34;, 6379);
	// 游标
	String cursor = &#34;0&#34;;
	while(true) {
		ScanResult&lt;Map.Entry&lt;String, String&gt;&gt; scanResult = jedis.hscan(bigKey, cursor, new ScanParams().count(100));
		// 每次扫描后获取新的游标
		cursor = scanResult.getStringCursor();		// 获取扫描结果
		List&lt;Entry&lt;String, String&gt;&gt; list = scanResult.getResult();		if(list == null || list.size() == 0) {
			continue;		}		String[] fields = getFieldsFrom(list);		// 删除多个field
		jedis.hdel(bigKey, fields);		// 游标为0时停止
		if(cursor.equals(&#34;0&#34;)) {
			break;
		}	}	// 最终删除key
	jedis.del(bigKey);
}
/**
 * 获取field数组 */
private String[] getFieldsFrom(List&lt;Entry&lt;String, String&gt;&gt; list) {
	List&lt;String&gt; fields = new ArrayList&lt;String&gt;();
	for (Entry&lt;String, String&gt; entry : list) {
		fields.add(entry.getKey());
	}
	return fields.toArray(new String[fields.size()]);
}</code></pre></div>
<h2 id="3-list">3. list</h2>

<p>Redis并没有提供lscan这样的API来遍历列表类型，但是提供了ltrim这样的命令可以渐进式的删除列表元素，直到把列表删除。</p>
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">public void delBigList(String bigKey) {
	Jedis jedis = new Jedis(&#34;127.0.0.1&#34;, 6379);
	long llen = jedis.llen(bigKey);
	int counter = 0;
	int left = 100;
	while(counter &lt; llen) {
		// 每次从左侧截掉100个
		jedis.ltrim(bigKey, left, llen);
		counter += left;
	}
	// 最终删除key
	jedis.del(bigKey);
}</code></pre></div>
<h2 id="4-set">4. set</h2>

<p>使用sscan命令，每次获取部分(例如100个)元素，在利用srem删除每个元素。</p>
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">public void delBigSet(String bigKey) {
	Jedis jedis = new Jedis(&#34;127.0.0.1&#34;, 6379);
	// 游标
	String cursor = &#34;0&#34;;
	while(true) {
		ScanResult&lt;String&gt; scanResult = jedis.sscan(bigKey, cursor, new ScanParams().count(100));
		// 每次扫描后获取新的游标
		cursor = scanResult.getStringCursor();		// 获取扫描结果
		List&lt;String&gt; list = scanResult.getResult();		if(list == null || list.size() == 0) {
			continue;
		}				jedis.srem(bigKey, list.toArray(new String[list.size()]));
		// 游标为0时停止
		if(cursor.equals(&#34;0&#34;)) {
			break;
		}	}	// 最终删除key
	jedis.del(bigKey);}</code></pre></div>
<h2 id="5-sorted-set">5. sorted set</h2>

<p>使用zscan命令，每次获取部分(例如100个)元素，在利用zremrangebyrank删除元素。</p>
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">public void delBigSortedSet(String bigKey) {
	long startTime = System.currentTimeMillis();	Jedis jedis = new Jedis(HOST, PORT);	// 游标
	String cursor = &#34;0&#34;;
	while(true) {
		ScanResult&lt;Tuple&gt; scanResult = jedis.zscan(bigKey, cursor, new ScanParams().count(100));
		// 每次扫描后获取新的游标
		cursor = scanResult.getStringCursor();		// 获取扫描结果
		List&lt;Tuple&gt; list = scanResult.getResult();		if(list == null || list.size() == 0) {
			continue;		}		String[] members = getMembers(list);		jedis.zrem(bigKey, members);		// 游标为0时停止
		if(cursor.equals(&#34;0&#34;)) {
			break;
		}	}	// 最终删除key
	jedis.del(bigKey);
}
public void delBigSortedSet2(String bigKey) {
	Jedis jedis = new Jedis(HOST, PORT);
	long zcard = jedis.zcard(bigKey);
	int counter = 0;
	int incr = 100;
	while(counter &lt; zcard) {
		jedis.zremrangeByRank(bigKey, 0, 100);
		// 每次从左侧截掉100个
		counter += incr;
	}
	// 最终删除key
	jedis.del(bigKey);
}</code></pre></div>
<h2 id="六-如何优化"><strong>六、如何优化</strong></h2>

<h2 id="1-拆分">1.拆分</h2>

<p>big list： list1、list2、&hellip;listN</p>

<p>big hash：可以做二次的hash，例如hash%100</p>

<p>日期类：key20190320、key20190321、key_20190322。</p>

<h2 id="2-本地缓存">2.本地缓存</h2>

<p>减少访问redis次数，降低危害，但是要注意这里有可能因此本地的一些开销（例如使用堆外内存会涉及序列化，bigkey对序列化的开销也不小）</p>

<h2 id="7-总结"><strong>7、总结：</strong></h2>

<p>由于开发人员对Redis的理解程度不同，在实际开发中出现bigkey在所难免，重要的能通过合理的检测机制及时找到它们，进行处理。作为开发人员应该在业务开发时不能将Redis简单暴力的使用，应该在数据结构的选择和设计上更加合理，例如出现了bigkey，要思考一下可不可以做一些优化(例如二级索引)尽量的让这些bigkey消失在业务中，如果bigkey不可避免，也要思考一下要不要每次把所有元素都取出来(例如有时候仅仅需要hmget，而不是hgetall)，删除也是一样，尽量使用优雅的方式来处理。</p>

    </div>
    <footer class="post-footer">
     

     <div class="post-nav">
    <div class="post-nav-next post-nav-item">
    
        <a href="http://www.shutdown.cn/post/redis-aof%E6%9C%89%E5%93%AA%E4%BA%9B%E6%BD%9C%E5%9C%A8%E7%9A%84%E9%98%BB%E5%A1%9E%E7%82%B9/" rel="next" title="">
        <i class="fa fa-chevron-left"></i> 
        </a>
    
    </div>

    <div class="post-nav-prev post-nav-item">
    
        <a href="http://www.shutdown.cn/post/redis-cpu%E9%AB%98%E6%8E%92%E6%9F%A5%E8%BF%87%E7%A8%8B/" rel="prev" title="">
         <i class="fa fa-chevron-right"></i>
        </a>
    
    </div>
</div>
      
     
     
     






    </footer>
  </article>
</section>

          </div>
        </div>
        <div class="sidebar-toggle">
  <div class="sidebar-toggle-line-wrap">
    <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
    <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
    <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
  </div>
</div>
<aside id="sidebar" class="sidebar">
  <div class="sidebar-inner">

    <section class="site-overview sidebar-panel  sidebar-panel-active ">
      <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image"
        src="http://www.shutdown.cn/img/author.jpg"
        alt="不与天斗Domino" />
    <p class="site-author-name" itemprop="name">不与天斗Domino</p>
    <p class="site-description motion-element" itemprop="description"> 
        Programmer &amp; Architect</p>
</div>
      <nav class="site-state motion-element">
    <div class="site-state-item site-state-posts">
      <a href="http://www.shutdown.cn/post/">
        <span class="site-state-item-count">171</span>
        <span class="site-state-item-name">日志</span>
      </a>
    </div>
    <div class="site-state-item site-state-categories">    
        <a href="http://www.shutdown.cn/categories/">      
         
        <span class="site-state-item-count">12</span>
        
        <span class="site-state-item-name">分类</span>
        
        </a>
    </div>

    <div class="site-state-item site-state-tags">
        <a href="http://www.shutdown.cn/tags/">
         
        <span class="site-state-item-count">182</span>
        
        <span class="site-state-item-name">标签</span>
        </a>
    </div>
</nav>
      
      

      

      <div class="links-of-blogroll motion-element inline">
<script type="text/javascript" src="//rf.revolvermaps.com/0/0/8.js?i=&amp;m=0&amp;s=220&amp;c=ff0000&amp;cr1=ffffff&amp;f=arial&amp;l=33&amp;bv=35" async="async"></script>
</div>

    </section>
    
  </div>
</aside>

      </div>
    </main>
   
    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright" >
  <span itemprop="copyrightYear">  &copy; 
  2013 - 2022</span>
  <span class="with-love"><i class="fa fa-heart"></i></span>
  <span class="author" itemprop="copyrightHolder">天地维杰网</span>
  <span class="icp" itemprop="copyrightHolder"><a href="https://beian.miit.gov.cn/" target="_blank">京ICP备13019191号-1</a></span>
</div>
<div class="powered-by">
  Powered by - <a class="theme-link" href="http://gohugo.io" target="_blank" title="hugo" >Hugo v0.63.2</a>
</div>
<div class="theme-info">
  Theme by - <a class="theme-link" href="https://github.com/xtfly/hugo-theme-next" target="_blank"> NexT
  </a>
</div>


      </div>
    </footer>

    <div class="back-to-top">
      <i class="fa fa-arrow-up"></i>
      <span id="scrollpercent"><span>0</span>%</span>
    </div>
  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>
<script type="text/javascript" src="http://www.shutdown.cn/js/vendor/jquery/index.js?v=2.1.3"></script>
<script type="text/javascript" src="http://www.shutdown.cn/js/vendor/fastclick/lib/fastclick.min.js?v=1.0.6"></script> 
<script type="text/javascript" src="http://www.shutdown.cn/js/vendor/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>
<script type="text/javascript" src="http://www.shutdown.cn/js/vendor/velocity/velocity.min.js?v=1.2.1"></script>
<script type="text/javascript" src="http://www.shutdown.cn/js/vendor/velocity/velocity.ui.min.js?v=1.2.1"></script>
<script src="http://www.shutdown.cn/js/vendor/ua-parser-js/dist/ua-parser.min.js?v=0.7.9"></script>

<script src="http://www.shutdown.cn/js/vendor/fancybox/jquery.fancybox.pack.js?v=2.1.5"></script>

<script type="text/javascript" src="http://www.shutdown.cn/js/utils.js"></script>
<script type="text/javascript" src="http://www.shutdown.cn/js/motion.js"></script>
<script type="text/javascript" src="http://www.shutdown.cn/js/affix.js"></script>
<script type="text/javascript" src="http://www.shutdown.cn/js/schemes/pisces.js"></script>

<script type="text/javascript" src="http://www.shutdown.cn/js/scrollspy.js"></script>
<script type="text/javascript" src="http://www.shutdown.cn/js/post-details.js"></script>
<script type="text/javascript" src="http://www.shutdown.cn/js/toc.js"></script>

<script type="text/javascript" src="http://www.shutdown.cn/js/bootstrap.js"></script>

<script type="text/javascript" src="http://www.shutdown.cn/js/search.js"></script>
<script type="text/x-mathjax-config">
  MathJax.Hub.Config({
    extensions: ["tex2jax.js"],
    jax: ["input/TeX", "output/HTML-CSS"],
    tex2jax: {
      inlineMath: [ ['$','$'] ],
      displayMath: [ ['$$','$$'] ],
      processEscapes: true
    },
    "HTML-CSS": { fonts: ["TeX"] }
  });
</script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_HTMLorMML' async></script>
</body>
</html>